/** 
 *  @file
 *  @brief   可扩展的单元工厂
 *  @author  wanghuan
 *  @date    2023.11.06
 *  @version v1.0
 *  @par Copyright(c):  ShenGong  Simulation corporation
 */
#pragma once
#include <map>
#include "../Common/ElementCalculatorExport.h"
#include "../Interface/IElementCalculator.h"

SG_FEMSOLVER_ELEMENT_NAMESPACE_OPEN

/** @brief 可扩展的单元计算工厂类
 * 
 *     首先应该使用 Register 函数将指向派生类对象的静态函数做为回调函数传入工厂。
 * 完成对派生类的注册</p>
 *     计算时，调用 ElementCalculatorFactory::Create（）触发对`具体单元计算派生类`的创建
 */ 
class ElementCalculator_DECLSPEC ElementCalculatorFactory
{
public:
    /// 定义函数指针 `ElementCreateFuncPtr`
    typedef ElementCalculatorSP (*ElementCreateFuncPtr) ();

    /** @brief 注册单元计算类
     * @param type 单元计算派生类的`类型标识`
     * @param cb 函数指针, 绑定到 单元计算派生类的静态Create函数
     */
    static void Register (SG::DataStructure::FEM::ElementTypes type, ElementCreateFuncPtr cb);
    
    /** @brief 注销 */
    static void UnRegister (SG::DataStructure::FEM::ElementTypes type);

    /** @brief 创建派生类对象
     * @return 当找不到对应单元类型，将返回空
     * 
     * 调用此函数时， 会触发`type`对应的派生类的回调函数，返回一个指向派生类的基类指针。
     */
    static ElementCalculatorSP Create (SG::DataStructure::FEM::ElementTypes type);

private:
    using ElementTypeMap = std::map<SG::DataStructure::FEM::ElementTypes, ElementCreateFuncPtr>;
    static ElementTypeMap s_elements;
};
SG_FEMSOLVER_ELEMENT_NAMESPACE_CLOSE